package com.lsa.iview.unsorted;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import junit.framework.TestCase;

import org.junit.Assert;

import com.lsa.helpers.ISimpleClosure;
import com.lsa.helpers.Utils;

public class SmallTasksTest extends TestCase {
	public void testPalindromeNumber() {
		Assert.assertTrue(SmallTasks.isPalindrome(1221));
		Assert.assertTrue(SmallTasks.isPalindrome(12321));
		Assert.assertTrue(SmallTasks.isPalindrome(5678765));
		Assert.assertTrue(!SmallTasks.isPalindrome(1232));
	}
	
	public void testRempoveSpacesInPlace() {
		testRempoveSpacesInPlace("123");
		testRempoveSpacesInPlace("123123");
		testRempoveSpacesInPlace("");
		testRempoveSpacesInPlace("         ");
		testRempoveSpacesInPlace("123 123        123 12 s   5");
		testRempoveSpacesInPlace("123 123        123 12 s   5 ");
		testRempoveSpacesInPlace(" 123 123        123 12 s   5");
		testRempoveSpacesInPlace(" 1 12  123     1234 12345      123456");
	}
	
	public void testCountWords() {
		testCountWords("123", 1);
		testCountWords("123 123", 2);
		testCountWords("123 123 123", 3);
		testCountWords("123123", 1);
		testCountWords("", 0);
		testCountWords("         ", 0);
		testCountWords("123 123        123 12 s   5", 6);
		testCountWords("123 123        123 12 s   5 ", 6);
		testCountWords(" 123 123        123 12 s   5", 6);
		testCountWords(" 1 12  123     1234 12345      123456", 6);
	}
	
	public void testPutchar() {
		testPutchar(123);
		testPutchar(1234);
		testPutchar(1);
		testPutchar(0);
		testPutchar(123454321);
	}
	
	public void testBitwise() {
		xorSwap();
		xorBitwise();
	}
	
	public static void testRotate() {
		//For instance, with n=7 and k=3, the array {a, b, c, d, e, f, g} is rotated to {e, f, g, a, b, c, d}.
		int[] expected = SmallTasks.rotate(new int[]{'a', 'b', 'c', 'd', 'e', 'f', 'g'}, 3);
		Arrays.equals(new int[]{'e', 'f', 'g', 'a', 'b','c', 'd', 'a'}, expected);
		
		int[] actual = new int[]{'a', 'b', 'c', 'd', 'e', 'f', 'g'};
		SmallTasks.rotateInplace(actual, 3);
		Arrays.equals(expected, actual);
	}
	
	private void xorBitwise() {
	}

	private void xorSwap() {
		int x = 119;
		int y = 20585;
		
		System.out.println(String.format("Before xor swap : %s %s", x, y));
		x = x ^ y;
		y = x ^ y;
		x = x ^ y;
		System.out.println(String.format("After xor swap : %s %s", x, y));
	}

	private void testPutchar(int n) {
		Assert.assertEquals(""+n, SmallTasks.putchar(n));
	}

	private void testCountWords(String text, int expectedCnt) {
		Assert.assertEquals(expectedCnt, SmallTasks.countWords(text));
	}
	
	private void testRempoveSpacesInPlace(String s) {
		Assert.assertEquals(removeSpacesInPlace(s), SmallTasks.removeSpacesInPlace(s.toCharArray()));
	}
	
	private static String removeSpacesInPlace(String s) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < s.length(); i++) {
			char c = s.charAt(i);
			if (!Character.isWhitespace(c)) {
				sb.append(c);
			}
		}
		return sb.toString();
	}
	
	public void testSkippedProduct() {
		int[] arr = new int[] { 1, 2, 3, 4, 5};
		int[] expected = SmallTasks.skippedProductTest(arr);
		int[] expectedExpected = new int[] { 2 * 3 * 4 * 5, 1 * 3 * 4 * 5, 1 * 2 * 4 * 5, 1 * 2 * 3 * 5, 1 *  2 * 3 * 4};
		Assert.assertTrue(Arrays.equals(expectedExpected, expected));
		int[] skipped = SmallTasks.skippedProduct(arr);
		Assert.assertTrue(Arrays.equals(expected, skipped));
		
		arr = new int[] { 10, 20, 30, 40, 50};
		expected = SmallTasks.skippedProductTest(arr);
		expectedExpected = new int[] { 20 * 30 * 40 * 50, 10 * 30 * 40 * 50, 10 * 20 * 40 * 50, 10 * 20 * 30 * 50, 10 *  20 * 30 * 40};
		Assert.assertTrue(Arrays.equals(expectedExpected, expected));
		skipped = SmallTasks.skippedProduct(arr);
		Assert.assertTrue(Arrays.equals(expected, skipped));
		
		arr = Utils.createIntArray1D(1, 30, 7);
		expected = SmallTasks.skippedProductTest(arr);
		skipped = SmallTasks.skippedProduct(arr);
		Assert.assertTrue(Arrays.equals(expected, skipped));
		
		arr = Utils.createIntArray1D(3, 13, 1);
		expected = SmallTasks.skippedProductTest(arr);
		skipped = SmallTasks.skippedProduct(arr);
		Assert.assertTrue(Arrays.equals(expected, skipped));
	}
	
	public void testPrimes() {
		List<Integer> expected = Arrays.asList(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997);
		Assert.assertEquals("",expected, SmallTasks.primes(1000));
	}
	
	public void testSumToTarget() {
		testSumToTarget(6, new int[]{1, 2, 3, 4, 5, 6}, new int[][]{{1, 2, 3}, {1, 5}, {2, 4}, {6}});
		testSumToTarget(7, new int[]{1, 2, 3, 4, 5, 6, 7}, new int[][]{{1, 2, 4}, {1, 6}, {2, 5}, {3, 4}, {7}});
	}
	
	private void testSumToTarget(int target, int[] elements, int[][] expectedResults) {
		List<List<Integer>> expected = new ArrayList<List<Integer>>();
		for (int[] res : expectedResults) {
			List<Integer> e = new ArrayList<Integer>();
			for (int i : res) {
				e.add(i);
			}
			expected.add(e);
		}
		final List<List<Integer>> results = new ArrayList<List<Integer>>();
		SmallTasks.sumsToTarget(target, elements, new ISimpleClosure<List<Integer>>() {
			@Override
			public Void invoke(List<Integer> t) throws RuntimeException {
				results.add(t);
				return null;
			}
		});
		sort(expected);
		sort(results);
		Assert.assertEquals(expected, results);
	}
	
	private void sort(List<List<Integer>> lists) {
		Collections.sort(lists, new Comparator<List<Integer>>() {
			@Override
			public int compare(List<Integer> l1, List<Integer> l2) {
				if (l1.size() > l2.size()) {
					List<Integer> t = l1;
					l1 = l2;
					l2 = t;
				}
				for (int i = 0; i < l1.size(); i++) {
					int res = l1.get(i) - l2.get(i);
					if (res != 0){
						return res;
					}
				}
				return l1.size() - l2.size();
			}
		});
	}
	
	public static void testPow() {
		Assert.assertEquals(32L, (long)SmallTasks.pow(2, 5));
		Assert.assertEquals((long)Math.pow(2, 37), (long)SmallTasks.pow(2, 37));
		Assert.assertEquals((long)Math.pow(5, 13), (long)SmallTasks.pow(5, 13));
		Assert.assertEquals((long)Math.pow(5, 17), (long)SmallTasks.pow(5, 17));
	}
}
